{% macro table(table_id, data, columns, actions, routes, selected_items=[], selectable=true, input_name="selected_items", standalone=true) %}
  {% from "macros/table.html" import table_header, table_controls %}
  {% from "macros/buttons.html" import action_button %}
  {% set item_ids = data | map(attribute='id') | list %}
  <table class="table shadow table-zebra table-sm"
         id="{{ table_id }}"
         data-testid="{{ table_id }}"
         {% if standalone %}x-data="{ selectedItems: {{ selected_items }} }"{% endif %}>
    <thead>
      <tr>
        {% if selectable %}
          <th>
            <input type="checkbox"
                   class="checkbox"
                   :checked="selectedItems.length === {{ item_ids | length }}"
                   @change="selectedItems = selectedItems.length === {{ item_ids | length }} ? [] : {{ item_ids }}"
                   @click.stop />
          </th>
        {% endif %}
        {% for col in columns %}{{ table_header(col) }}{% endfor %}
        {% if actions %}<th class="text-right">Actions</th>{% endif %}
      </tr>
    </thead>
    <tbody>
      {% if data %}
        {% for item in data %}
          {% set edit_route = routes.edit_route[:-1] ~ item.id %}
          <tr class="hover:bg-info">
            {% if selectable %}
              <td>
                <input type="checkbox" class="checkbox checkbox-sm" value="{{ item.id }}" name="{{ input_name }}[]" x-model="selectedItems" @click.stop />
              </td>
            {% endif %}
            {% for col in columns %}
              <td class="relative max-w-[50ch] p-0">
                <a href="{{ edit_route }}" class="flex w-full items-center px-3 py-1 truncate">
                  {% if col.renderer %}
                    {% if 'render_args' in col %}
                      {{ col.renderer(item, **col.render_args) }}
                    {% else %}
                      {{ col.renderer(item) }}
                    {% endif %}
                  {% else %}
                    {{ item[col.field] }}
                  {% endif %}
                </a>
              </td>
            {% endfor %}
            {% if actions %}
              {% from "macros/table.html" import table_actions %}
              {{ table_actions(actions, item.id, routes.base_route) }}
            {% else %}
            {% endif %}
          </tr>
        {% endfor %}
      {% else %}
        <tr>
          <td colspan="{{ (columns|length + (1 if selectable else 0) + (1 if actions else 0)) }}">
            <div class="text-center">
              <p class="text-gray-500">No data available</p>
            </div>
          </td>
        </tr>
      {% endif %}
    </tbody>
    <tfoot hx-target="#{{ table_id }}-container" hx-swap="outerHTML">
      <tr>
        <td colspan="{{ (columns|length + (1 if selectable else 0) + (1 if actions else 0)) }}">
          <div class="flex justify-center">{{ table_controls(base_url=routes.base_route, data=data) }}</div>
        </td>
      </tr>
    </tfoot>
  </table>
{% endmacro %}

{% macro table_actions(actions, item_id, base_url) %}
  {% from "macros/buttons.html" import action_button %}
  <td class="relative text-right max-w-[50ch] p-0">
    {% if actions is sameas true %}
      {% set actions = [
              {
                'label': 'Edit',
                'class': 'btn-primary',
                'icon': 'pencil-square',
                'url': base_url,
                'is_link': true
              },
              {
                'label': 'Delete',
                'icon': 'trash',
                'class': 'btn-error',
                'method': 'delete',
                'url': base_url,
                'hx_target': None,
                'hx_swap': None,
                'confirm': 'Are you sure you want to delete this item?'
              }
            ] %}
    {% endif %}
    {% for action in actions %}{{ action_button(action, item_id=item_id) }}{% endfor %}
  </td>
{% endmacro %}

{% macro table_decoration(name, model_name, container_id, routes, searchbar=true, new_item_target="#form-container") %}
  <div class="flex gap-4 mb-4">
    {% if routes.edit_route %}
      <div class="grow-0">
        <button hx-get="{{ routes.edit_route }}"
                hx-push-url="true"
                hx-target="{{ new_item_target }}"
                class="btn btn-primary"
                data-testid="new-{{ model_name }}-button">New {{ name }}</button>
      </div>
    {% endif %}
    {% if searchbar %}{{ table_search_bar(container_id, routes.base_route) }}{% endif %}
    {% if routes.edit_route %}
      <div class="grow-0">
        <button type="button"
                class="btn btn-error"
                data-testid="delete-{{ model_name }}-button"
                :hx-vals="JSON.stringify({ ids: selectedItems })"
                hx-delete="{{ delete_route }}"
                hx-confirm="Are you sure you want to delete the selected items?"
                hx-target="#{{ container_id }}"
                :disabled="selectedItems.length === 0">
          Delete <span x-text="selectedItems.length" x-show="selectedItems.length > 0"></span> {{ name }}
        </button>
      </div>
    {% endif %}
    {% if caller is defined %}{{ caller() }}{% endif %}
  </div>
{% endmacro %}

{% macro table_header(column) %}
  {% from "macros/query_params.html" import update_query_params %}
  {% set order_direction = 'asc' if request.args.get('order') != column.field ~ '_asc' else 'desc' %}
  {% set order = column.field ~ '_' ~ order_direction %}
  {% set order_params = {'order': order, 'page': 1} %}
  {% set order_url = update_query_params(order_params) %}
  {% if column.sortable %}
    <th hx-boost>
      <a href="{{ order_url }}" hx-target="closest table" hx-push-url="true" class="link link-hover">
        {{ column.title }}
        {% if request.args.get('order', '').startswith(column.field) %}
          {% if request.args.get('order').endswith('_asc') %}
            ▲
          {% else %}
            ▼
          {% endif %}
        {% endif %}
      </a>
    </th>
  {% else %}
    <th>{{ column.title }}</th>
  {% endif %}
{% endmacro %}

{% macro table_search_bar(table_id, base_url) %}
  {% set current_search = request.args.get('search', '') %}
  <div class="grow">
    <form hx-get="{{ base_url }}"
          hx-push-url="true"
          hx-select="#{{ table_id }}"
          hx-target="#{{ table_id }}"
          hx-target-error="#notification-bar"
          hx-trigger="input delay:500ms"
          hx-on::after-swap="document.getElementById('{{ table_id }}-search').focus()">
      <label class="input w-full">
        {{ heroicon_outline('magnifying-glass', class="h-5 w-5") }}
        <input type="search" id="{{ table_id }}-search" name="search" placeholder="Search..." value="{{ current_search }}" />
      </label>
    </form>
  </div>
{% endmacro %}

{% macro table_controls(base_url, data) %}
  {% from "macros/query_params.html" import update_query_params %}
  {% if data and base_url %}
    <div class="flex items-center gap-8 p-4 bg-base-100 shadow rounded-lg w-fit">
      <!-- Items per Page -->
      <div class="flex items-center gap-2">
        <span class="text-sm font-medium">Items per page:</span>
        <select name="limit"
                class="select select-bordered select-sm h-8"
                hx-get="{{ base_url }}{{ update_query_params({'page': 1}, exclude=['limit']) }}"
                hx-include="this"
                hx-push-url="true">
          {% for option in [5, 20, 50, 100] %}
            <option value="{{ option }}" {% if data.limit == option %}selected{% endif %}>{{ option }}</option>
          {% endfor %}
        </select>
      </div>

      <!-- Pagination Buttons & Current Page -->
      <div class="flex items-center gap-2">
        <a {% if data.first_page %}hx-disable{% endif %}
           class="btn btn-sm h-8 min-w-[2rem] {% if data.first_page %}opacity-50 cursor-not-allowed{% endif %}"
           hx-get="{{ base_url }}{{ update_query_params({"page": 1}) }}"
           hx-push-url="true">«</a>

        <a {% if data.first_page %}hx-disable{% endif %}
           class="btn btn-sm h-8 min-w-[2rem] {% if data.first_page %}opacity-50 cursor-not-allowed{% endif %}"
           hx-get="{{ base_url }}{{ update_query_params({'page': data.current_page - 1}) }}"
           hx-push-url="true">‹</a>

        <span class="px-3 py-1 h-8 flex items-center bg-base-200 rounded-md text-sm font-semibold">
          Page {{ data.current_page }} of {{ data.total_pages }}
        </span>

        <a {% if data.last_page %}hx-disable{% endif %}
           class="btn btn-sm h-8 min-w-[2rem] {% if data.last_page %}opacity-50 cursor-not-allowed{% endif %}"
           hx-get="{{ base_url }}{{ update_query_params({'page': data.current_page + 1}) }}"
           hx-push-url="true">›</a>

        <a {% if data.last_page %}hx-disable{% endif %}
           class="btn btn-sm h-8 min-w-[2rem] {% if data.last_page %}opacity-50 cursor-not-allowed{% endif %}"
           hx-get="{{ base_url }}{{ update_query_params({'page': data.total_pages}) }}"
           hx-push-url="true">»</a>
      </div>
    </div>
  {% endif %}
{% endmacro %}
